const express = require("express");
const mongoose = require("mongoose");
const jwt = require("jsonwebtoken");
const multer = require("multer");
const axios = require("axios");
const path = require("path");
const crypto = require("crypto");
const fs = require("fs");

const UserSchema = new mongoose.Schema({
  username: String,
  password: String,
  nickname: String,
  phone: String,
  openid: String,
});

const userModel = mongoose.model("user", UserSchema);

// 解密微信数据的方法
function decryptData(sessionKey, encryptedData, iv) {
  // base64 decode
  var sessionKey = Buffer.from(sessionKey, "base64");
  encryptedData = Buffer.from(encryptedData, "base64");
  iv = Buffer.from(iv, "base64");

  try {
    // 解密
    var decipher = crypto.createDecipheriv("aes-128-cbc", sessionKey, iv);
    // 设置自动 padding 为 true，删除填充补位
    decipher.setAutoPadding(true);
    var decoded = decipher.update(encryptedData, "binary", "utf8");
    decoded += decipher.final("utf8");

    decoded = JSON.parse(decoded);

    return decoded;
  } catch (err) {
    throw new Error("Illegal Buffer");
  }
}

// 配置multer, 得到一个中间件
const upload = multer({
  dest: "./uploads", // 上传过来的文件的临时存放路径
  fileFilter: (req, file, callback) => {
    // 过滤的处理
    // callback(new Error("文件太大了"), false); // 不走下面，直接报错
    // callback(null, true); // 放行

    console.log("file", file);
    const fileTypes = ["image/jpeg", "image/png", "image/gif"];
    if (!fileTypes.includes(file.mimetype)) {
      return callback(new Error("文件类型不正确"), false); // 不走下面，直接报错
    }

    callback(null, true);
  },
  limits: {
    fileSize: 1024 * 100, // 文件大小限制，单位是字节
  },
});

const app = express();

// 设置静态资源托管目录
app.use(express.static(path.join(__dirname, "./public")));

// 设置json转换，让 req.body 有内容
app.use(express.json());

// 文件上传
app.post("/upload", upload.single("file"), (req, res) => {
  // 经过 multer 处理之后，req 对象上会存在一个 file 的属性，该属性就是文件相关的内容
  console.log(req.file);

  // 读文件内容
  const fileData = fs.readFileSync(req.file.path, "binary");
  // 写文件
  //    1. 构建一个文件名
  const filename = req.file.filename + path.extname(req.file.originalname);
  console.log("filename", filename);
  //    2. 基于文件名，构建出最终文件的储存路径
  const filepath = path.join(__dirname, "./public", filename);
  console.log("filepath", filepath);
  //    3. 开始写入
  fs.writeFileSync(filepath, fileData, "binary");

  res.send({
    status: 0,
    msg: "上传成功",
    data: `http://localhost:3000/${filename}`,
  });
});

// 微信登录接口
app.post("/loginByWx", async (req, res) => {
  // 1. 获取前端传递过来的参数
  const { code } = req.body;
  // 2. 调用微信提供的 code2session 接口
  const response = await axios.get(
    "https://api.weixin.qq.com/sns/jscode2session",
    {
      params: {
        appid: "wx9c67de3c3bbe281c",
        secret: "5bcdd24175928251d8f326388f188359",
        js_code: code,
        grant_type: "authorization_code",
      },
    }
  );
  // 3. 解构出 openid 与 session_key
  const { openid, session_key } = response.data;
  // 4. 判断一下
  if (!openid) {
    // 返回错误
    return res.send({ code: -1, msg: "有错误" });
  }
  // 5. 根据 openid 查询用户表，查询不到就干一个注册的事情。
  let userInfo = await userModel.findOne({ openid: openid });
  const count = await userModel.find().countDocuments(); // 条数
  console.log("userInfo", userInfo);
  if (!userInfo) {
    console.log("1111");
    // 不存在，主动给它注册一下
    userInfo = await userModel.create({
      username: `user_${count + 1}`,
      password: `user_${count + 1}`,
      nickname: `user_${count + 1}`,
      phone: "",
      openid,
    });
  }
  // 6. 处理登录状态，签发token
  const token = jwt.sign(
    {
      id: userInfo._id,
      nickname: userInfo.nickname,
      openid: userInfo.openid,
    },
    "HELLO WORLD",
    {
      expiresIn: "10d",
    }
  );
  // 7. 响应成功
  res.send({
    code: 0,
    msg: "ok",
    data: {
      openid: openid,
      token: token,
    },
  });
});

// 微信登录接口，携带有手机号加密数据的
app.post("/loginByWx2", async (req, res) => {
  // 1. 获取前端传递过来的参数
  const { code, encryptedData, iv } = req.body;
  // 2. 调用微信提供的 code2session 接口
  const response = await axios.get(
    "https://api.weixin.qq.com/sns/jscode2session",
    {
      params: {
        appid: "wx9c67de3c3bbe281c",
        secret: "5bcdd24175928251d8f326388f188359",
        js_code: code,
        grant_type: "authorization_code",
      },
    }
  );
  // 3. 解构出 openid 与 session_key
  const { openid, session_key } = response.data;
  // 4. 判断一下
  if (!openid) {
    // 返回错误
    return res.send({ code: -1, msg: "有错误" });
  }
  // 4. 解密手机号数据
  const data = decryptData(session_key, encryptedData, iv);
  console.log("解密的数据：", data);
  // 5. 根据 openid 查询用户表，查询不到就干一个注册的事情。
  let userInfo = await userModel.findOne({ openid: openid });
  const count = await userModel.find().countDocuments(); // 条数
  console.log("userInfo", userInfo);
  if (!userInfo) {
    console.log("1111");
    // 不存在，主动给它注册一下
    userInfo = await userModel.create({
      username: `user_${count + 1}`,
      password: `user_${count + 1}`,
      nickname: `user_${count + 1}`,
      phone: data.phoneNumber,
      openid,
    });
  }
  // 6. 处理登录状态，签发token
  const token = jwt.sign(
    {
      id: userInfo._id,
      nickname: userInfo.nickname,
      openid: userInfo.openid,
    },
    "HELLO WORLD",
    {
      expiresIn: "10d",
    }
  );
  // 7. 响应成功
  res.send({
    code: 0,
    msg: "ok",
    data: {
      token: token,
    },
  });
});

app.listen(3000, () => {
  console.log("服务启动成功");

  // 建立数据库的链接
  mongoose.connect("mongodb://127.0.0.1:27017/hello");
});
